package com.api.apigateway.risk;

import com.api.apigateway.config.RiskConfig;
import com.api.common.utils.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;

/**
 * 规则引擎（轻量）
 * 运行逻辑：
 * - 基于特征与上下文的启发式规则产出风险分（0~1）与命中标签；
 * - 尽量保守（宁愿提示加严，不要直接拦截）。
 *
 * rulesEngine 针对突增、UA 异常、GET 带 body、长 query、低熵、匿名访问敏感路径等打风险分（越可疑分越高）。与“分高=风险高”的约定一致。
 */
@Slf4j
public class RulesEngine {

    private volatile RiskConfig riskConfig;




    /** 返回规则风险分（0~1），命中严重规则可直接抬分到 0.8+  (0 表示正常、1 表示异常)*/
    public double eval(RiskContext c, FeatureVector fv, Map<String,String> tagsOut){
        RiskConfig riskConfig=getRiskConfig();

        double score = 0.0;

        // 1) IP 秒级突增（qps_user_path 高 & delta_user_path 显著 > 3）
        double qps = fv.values.get("qps_user_path");
        double delta = fv.values.get("delta_user_path");
        if (qps >riskConfig.getQpsThreshold()  && delta > riskConfig.getDeltaThreshold()) { score += 0.5; tagsOut.put("burst", "1"); }

        // 2) UA 缺失或特别短（常见脚本/爬虫）
        int uaLen = (int)Math.round(fv.values.get("ua_len"));
        if (uaLen < riskConfig.getUaMinLength()) { score += 0.2; tagsOut.put("ua_suspect", "1"); }

        // 3) body/query 体积异常（大体积 GET / 超长参数）
        int body = (int)Math.round(fv.values.get("body_size"));
        int query = (int)Math.round(fv.values.get("query_size"));
        boolean isGet = fv.values.get("method_get") > 0.5;
        if (isGet && body > riskConfig.getBodySize()) { score += 0.2; tagsOut.put("get_with_body", "1"); }
        if (query > riskConfig.getQuerySize()) { score += 0.3; tagsOut.put("long_query", "1"); }

        // 4) IP 熵过低（集中打一个接口） -> 刷
        double H = fv.values.get("entropy_ip");
        if (H < riskConfig.getEntropy()) { score += 0.3; tagsOut.put("low_entropy", "1"); }

        // 5) 未登录但访问敏感路径
        boolean noUser = fv.values.get("has_user") < 0.5;
        if (noUser && c.path != null && (c.path.startsWith("/api/pay/") || c.path.startsWith("/api/finance/"))) {
            score += 0.4; tagsOut.put("anon_sensitive", "1");
        }

        // 限幅 0~1
        if (score > 1.0) score = 1.0;
        return score;
    }


    public RiskConfig getRiskConfig(){
        if(riskConfig==null){
            synchronized (this){
                try {
                    riskConfig= SpringContextUtils.getBean(RiskConfig.class);
                    log.info("已加载 RiskConfig：{}",riskConfig.getClass().getSimpleName());
                }catch (Exception e){
                    log.warn("未找到 RiskConfig");
                }
            }
        }

        return riskConfig;
    }
}